package webServer

import (
	"bytes"
	"encoding/json"
	"expvar"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"testing"

	"lxb.com/bot_mock/webserver/server/bot"
	"lxb.com/bot_mock/webserver/server/chat"
	"lxb.com/bot_mock/webserver/server/wqas"
)

// expvar 是一个公共变量标准接口包，提供原子级别的公共变量读写操作
var helloRequests = expvar.NewInt("hello-requests")

var webroot = flag.String("root", "/home/user", "web root directory")

type Counter struct {
	n int
}

type Chan chan int

/*
	15.8示例

测试用例：

	http://localhost:12345/
	http://localhost:12345/go/hello
	http://localhost:12345/counter
	http://localhost:12345/go/ggg.html
	http://localhost:12345/flags
	http://localhost:12345/args
	http://localhost:12345/chan
	http://localhost:12345/date
*/

type Middleware func(http.Handler) http.Handler

func Chain(h http.Handler, middlewares ...Middleware) http.Handler {
	for i := len(middlewares) - 1; i >= 0; i-- {
		h = middlewares[i](h)
	}
	return h
}

func CORSMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Set CORS headers
		w.Header().Set("Access-Control-Allow-Origin", "*") // Allow all origins
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "*")

		// logrus.Debug("CORS Middleware========", r.Method, r.URL.Path)
		// Handle preflight OPTIONS request
		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusNoContent)
			return
		}

		next.ServeHTTP(w, r)
	})
}

func RequestLoggerMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 这个路径是浏览器 上面输入一个接口时，浏览器默认就会请求根路径下的/favicon.ico 网站图标，可以把这个忽略掉
		if r.URL.Path == "/favicon.ico" {
			// 直接交给下一个，不打印日志
			next.ServeHTTP(w, r)
			return
		}
		log.Print("===== request path ", r.URL.String())
		next.ServeHTTP(w, r)
	})
}

func Show_ElaboratedWebServer() {
	// port := "8081"
	// logrus.Printf("web server start at port %v, staring...\n", port)
	// !!! 这列如果不加 testing.Init() 那么就会报错，flag.Parse()的源码里会把 go test的test当做一个参数处理，而flag没有对这个参数做处理导致解析失败
	// 解决方式：
	//		1. 把 flag.Parse () 这行代码放到 main 函数里面，这样 go test 就不会走到这行代码
	//		2. 在 flag.Parse () 前面加上 testing.Init ()
	// 链接: https://my.oschina.net/u/3223370/blog/4272500
	testing.Init()
	flag.Parse()

	// // **************** start 直接注册路由额 start ****************
	// http.Handle("/", http.HandlerFunc(logger))
	// http.Handle("/go/hello", http.HandlerFunc(el_helloServer))
	// http.Handle("/user/login", http.HandlerFunc(login))
	// ctr := new(Counter)
	// expvar.Publish("counter", ctr)
	// http.Handle("/counter", ctr)
	// http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
	// http.Handle("/flags", http.HandlerFunc(flagServer))
	// http.Handle("/args", http.HandlerFunc(argServer))
	// http.Handle("/chan", chanCreate())
	// http.Handle("/date", http.HandlerFunc(dateServer))

	// // mock 接口
	// bot.ConfigHttpHandler()
	// chat.ConfigWebSocketHandler()
	// chat.ConfigAIChatHandler()

	// wqas.ConfigHttpHandler()

	// if err := http.ListenAndServe(":"+"8081", nil); err != nil {
	// 	// if err := http.ListenAndServe("192.168.3.2:"+port, nil); err != nil {
	// 	logrus.Fatal("failed to start server", err)
	// }
	// // **************** end 直接注册路由额 end ****************

	// **************** start 使用 mux 注册路由 start **************** //
	mux := http.NewServeMux()

	// Register handlers
	// handler := CORSMiddleware(mux)
	// 响应处理的时候是有匹配优先级的，比如 /go/hello 会优先匹配 /go/hello 而不会匹配 /go/ 这个路径，而不是 /
	mux.HandleFunc("/", http.HandlerFunc(logger)) // 由于匹配优先级的原因，这个打印请求的逻辑匹配到 /go/ 等路径时就不会打印了，采用日志中间件的形式实现
	mux.HandleFunc("/go/hello", http.HandlerFunc(el_helloServer))
	mux.HandleFunc("/user/login", http.HandlerFunc(login))
	mux.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
	mux.HandleFunc("/flags", http.HandlerFunc(flagServer))
	mux.HandleFunc("/args", http.HandlerFunc(argServer))
	mux.HandleFunc("/date", http.HandlerFunc(dateServer))
	mux.Handle("/chan", chanCreate())

	bot.ConfigWithMux(mux)

	wqas.ConfigHttpHandlerWithMux(mux)

	chat.ConfigWebSrocketWithMux(mux)
	chat.ConfigAIChatWithMux(mux)

	// **************** start 这里可以选择用 https 注册路由 start **************** //
	// cert, err := tls.LoadX509KeyPair("certs/cert.pem", "certs/key.pem")
	// if err != nil {
	// 	logrus.Fatal("failed to load key pair", err)
	// }
	// tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}}
	// server := &http.Server{
	// 	Addr:      "" + ":8088",
	// 	Handler:   handler, // http.DefaultServeMux,
	// 	TLSConfig: tlsConfig,
	// }
	// if err = server.ListenAndServeTLS("", ""); err != nil {
	// 	logrus.Fatal("failed to start server", err)
	// }
	// logrus.Print("Server in ended")
	// **************** end 使用 https 注册路由 end **************** //

	// **************** start 也可以用不使用https的方式 注册路由 start **************** //
	// 链式组合多个中间件
	wrappedMux := Chain(mux,
		RequestLoggerMiddleware,
		CORSMiddleware,
		// 以后还可以加更多 middleware
	)

	if err := http.ListenAndServe(":8802", wrappedMux); err != nil {
		// if err := http.ListenAndServe("192.168.3.2:"+port, nil); err != nil {
		log.Fatal("failed to start server", err)
	}
	// **************** end 也可以用不使用https的方式 注册路由 end **************** //

}

func ConfigHttpHandlerMux(mux *http.ServeMux) {
	panic("unimplemented")
}

// 日志打印
func logger(w http.ResponseWriter, req *http.Request) {
	if req.URL.Path == "/favicon.ico" {
		return
	}

	log.Print("logger======= ", req.URL.String())
	// w.WriteHeader(400)
	// w.Write([]byte("oops"))
}

func el_helloServer(w http.ResponseWriter, req *http.Request) {
	helloRequests.Add(1)
	io.WriteString(w, "hello, world!\n")
}

func login(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		w.Header().Set("Content-Type", "application/json")
		// 写入 sessionid 的方式代替 token
		r.ParseForm()
		log.Println("======GET========")
		log.Println("username: ", r.Form.Get("username"))
		log.Println("password: ", r.FormValue("password"))

		// 生成token
		// timestamp := strconv.Itoa(time.Now().Nanosecond())
		// hashWr := md5.New()
		// hashWr.Write([]byte(timestamp))
		// token := fmt.Sprintf("%x", hashWr.Sum(nil))
		// 这里会将token写入到模板里的 token input中
		// log.Println(t.Execute(w, token))
	case "POST":
		log.Println("======POST========")
		// 读取 body 数据
		len := r.ContentLength
		// 新建一个字节切片，长度与请求报文的内容长度相同
		body := make([]byte, len)
		// 读取 r 的请求主体，并将具体内容读入 body 中
		r.Body.Read(body)
		// 将字节切片内容写入相应报文
		fmt.Println("body is: ", string(body), "\n")

	}

	var response = make(map[string]interface{})
	response["code"] = 200
	response["msg"] = "success"
	response["data"] = map[string]string{"name": "test", "uid": "Xsssdsdsd"}

	jsonByte, _ := json.Marshal(response)
	str := string(jsonByte)
	log.Println("res: ", str)
	fmt.Println("res: ", str)
	io.WriteString(w, str)
}

func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }

func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	switch req.Method {
	case "GET":
		ctr.n++
	case "POST":
		buf := new(bytes.Buffer)
		io.Copy(buf, req.Body)
		body := buf.String()
		if n, err := strconv.Atoi(body); err != nil {
			fmt.Fprintf(w, "bad POST: %v\nbody: [%v]\n", err, body)
		} else {
			ctr.n = n
			fmt.Fprint(w, "counter reset\n")
		}
	}
	fmt.Fprintf(w, "counter = %d\n", ctr.n)
}

// 打印所有flag捕获的命令行参数（包括测试启动参数等 test开头的参数）
func flagServer(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	fmt.Fprint(w, "Flags:\n")
	flag.VisitAll(func(f *flag.Flag) {
		if f.Value.String() != f.DefValue {
			fmt.Fprintf(w, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue)
		} else {
			fmt.Fprintf(w, "%s = %s\n", f.Name, f.Value.String())
		}
	})
}

// 打印启动时的命令行参数
func argServer(w http.ResponseWriter, req *http.Request) {
	for _, s := range os.Args {
		fmt.Fprint(w, s, " ")
	}
}

func chanCreate() Chan {
	c := make(Chan)
	go func(c Chan) {
		for x := 0; ; x++ {
			c <- x
		}
	}(c)
	return c
}

func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, fmt.Sprintf("channel send #%d\n", <-ch))
}

/*
显示当前时间
/bin/date 只在 Unix 系统有效
*/
func dateServer(rw http.ResponseWriter, req *http.Request) {
	rw.Header().Set("Content-type", "text/plain; charset=utf-8")
	r, w, err := os.Pipe()
	if err != nil {
		fmt.Fprintf(rw, "pipe: %s\n", err)
		return
	}
	p, err := os.StartProcess("/bin/date",
		[]string{"date"},
		&os.ProcAttr{Files: []*os.File{nil, w, w}})
	defer r.Close()
	w.Close()
	if err != nil {
		fmt.Fprintf(rw, "fork/exec: %s\n", err)
		return
	}
	defer p.Release()
	io.Copy(rw, r)
	wait, err := p.Wait()
	if err != nil {
		fmt.Fprintf(rw, "wait: %s\n", err)
		return
	}
	if wait.Exited() {
		fmt.Fprintf(rw, "date: %v\n", wait)
		return
	}
}
